/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		ntds ldap lookup guid.cpp
 * PURPOSE:		NTDS over LDAP support
 *				type GUID lookup functions
 */

namespace Ldap
{

using namespace Lookup;
using namespace WorkQueue;

struct NtdsLookupObjTypeGuidWorkItem : LookupWorkItem<WCHAR>
{
	auto_refct<LdapConnection> Lc;
	auto_szpod<WCHAR> Text;
	ULONG SchemaLookup;
	ULONG ExtRtLookup;

	NtdsLookupObjTypeGuidWorkItem(CompletionTarget<WCHAR> *Ct, LdapConnection *Lc, GUID Guid) :
		LookupWorkItem(Ct),
		Lc(Lc)
	{
		PWSTR Attrs[] = {L"cn", NULL};
		LDAPControl *ServerCtrls[] = {&DomainScopeHintCtrl, NULL};

		{
			auto_szpod<WCHAR> GuidText = GuidToText(&Guid);

			ExtRtLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs, ServerCtrls, NULL, L"CN=Extended-Rights,CN=Configuration", SbtForest, L"rightsGuid=%1$s", GuidText);
		}
		{
			WCHAR GuidText[64]; //GUID text could be at most 49 characters

			RaiseOnLdapError(ldap_escape_filter_element(c_cast<PCHAR>(&Guid), sizeof Guid, GuidText, sizeof GuidText));

			SchemaLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs, ServerCtrls, NULL, L"CN=Schema,CN=Configuration", SbtForest, L"schemaIDGUID=%1$s", GuidText);
		}
	}

	virtual void Work() override
	{
		Result = AwaitSingleSearchResult<WCHAR>(Lc, ExtRtLookup, L"cn");
		ExtRtLookup = 0;
		if(!Result)
		{
			Result = AwaitSingleSearchResult<WCHAR>(Lc, SchemaLookup, L"cn");
			SchemaLookup = 0;
		}
		if(!Result)
			RaiseLdapError(LDAP_NO_SUCH_OBJECT);
	}

	~NtdsLookupObjTypeGuidWorkItem()
	{
		if(SchemaLookup)
			ldap_abandon(Lc->ld, SchemaLookup);
		if(ExtRtLookup)
			ldap_abandon(Lc->ld, ExtRtLookup);
	}
};

struct NtdsLookupObjTypeNameWorkItem : LookupWorkItem<GUID>
{
	auto_refct<LdapConnection> Lc;
	ULONG SchemaLookup;
	ULONG ExtRtLookup;

	NtdsLookupObjTypeNameWorkItem(CompletionTarget<GUID> *Ct, LdapConnection *Lc, PCWSTR Name) :
		LookupWorkItem(Ct),
		Lc(Lc)
	{
		LDAPControl *ServerCtrls[] = {&DomainScopeHintCtrl, NULL};

		PWSTR Attrs[] = {L"schemaIDGUID", NULL};
		SchemaLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs, ServerCtrls, NULL, L"CN=Schema,CN=Configuration", SbtForest, L"(&(objectClass=attributeSchema)(cn=%1$s))", Name);

		PWSTR Attrs2[] = {L"rightsGuid", NULL};
		ExtRtLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs2, ServerCtrls, NULL, L"CN=Extended-Rights,CN=Configuration", SbtForest, L"cn=%1$s", Name);
	}

	virtual void Work() override
	{
		Result = AwaitSingleSearchResult<GUID>(Lc, SchemaLookup, L"schemaIDGUID");
		SchemaLookup = 0;
		if(!Result)
		{
			auto_szpod<WCHAR> TextResult = AwaitSingleSearchResult<WCHAR>(Lc, ExtRtLookup, L"rightsGuid");
			Result = TextToGuid(TextResult);

			ExtRtLookup = 0;
		}
		if(!Result)
			RaiseLdapError(LDAP_NO_SUCH_OBJECT);
	}

	~NtdsLookupObjTypeNameWorkItem()
	{
		if(SchemaLookup)
			ldap_abandon(Lc->ld, SchemaLookup);
		if(ExtRtLookup)
			ldap_abandon(Lc->ld, ExtRtLookup);
	}
};

struct NtdsLookupObjInhTypeGuidWorkItem : LookupWorkItem<WCHAR>
{
	auto_refct<LdapConnection> Lc;
	auto_szpod<WCHAR> Text;
	ULONG SchemaLookup;

	NtdsLookupObjInhTypeGuidWorkItem(CompletionTarget<WCHAR> *Ct, LdapConnection *Lc, GUID Guid) :
		LookupWorkItem(Ct),
		Lc(Lc)
	{
		WCHAR GuidText[64]; //GUID text could be at most 49 characters
		PWSTR Attrs[] = {L"cn", NULL};
		LDAPControl *ServerCtrls[] = {&DomainScopeHintCtrl, NULL};

		RaiseOnLdapError(ldap_escape_filter_element(c_cast<PCHAR>(&Guid), sizeof Guid, GuidText, sizeof GuidText));

		SchemaLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs, ServerCtrls, NULL, L"CN=Schema,CN=Configuration", SbtForest, L"(&(objectClass=classSchema)(schemaIDGUID=%1$s))", GuidText);
	}

	virtual void Work() override
	{
		Result = AwaitSingleSearchResult<WCHAR>(Lc, SchemaLookup, L"cn");
		SchemaLookup = 0;
		if(!Result)
			RaiseLdapError(LDAP_NO_SUCH_OBJECT);
	}

	~NtdsLookupObjInhTypeGuidWorkItem()
	{
		if(SchemaLookup)
			ldap_abandon(Lc->ld, SchemaLookup);
	}
};

struct NtdsLookupObjInhTypeNameWorkItem : LookupWorkItem<GUID>
{
	auto_refct<LdapConnection> Lc;
	ULONG SchemaLookup;

	NtdsLookupObjInhTypeNameWorkItem(CompletionTarget<GUID> *Ct, LdapConnection *Lc, PCWSTR Name) :
		LookupWorkItem(Ct),
		Lc(Lc)
	{
		PWSTR Attrs[] = {L"schemaIDGUID", NULL};
		LDAPControl *ServerCtrls[] = {&DomainScopeHintCtrl, NULL};

		SchemaLookup = StartLdapSearchEx(Lc, LDAP_SCOPE_ONELEVEL, Attrs, ServerCtrls, NULL, L"CN=Schema,CN=Configuration", SbtForest, L"(&(objectClass=classSchema)(cn=%1$s))", Name);
	}

	virtual void Work() override
	{
		Result = AwaitSingleSearchResult<GUID>(Lc, SchemaLookup, L"schemaIDGUID");
		SchemaLookup = 0;
		if(!Result)
			RaiseLdapError(LDAP_NO_SUCH_OBJECT);
	}

	~NtdsLookupObjInhTypeNameWorkItem()
	{
		if(SchemaLookup)
			ldap_abandon(Lc->ld, SchemaLookup);
	}
};

struct GuidTypeTranslator : Lookup::Translator<GUID>
{
	auto_refct<LdapConnection> Lc;

	GuidTypeTranslator(LdapConnection *Lc) :
		Lc(Lc)
	{}
	GuidTypeTranslator(SDE_GENERIC_OPTS const &GenOpts, UCHAR Privileges) :
		Lc(new LdapConnection(Lc->Module, GenOpts, Privileges))
	{}
	void LookupData(CompletionTarget<WCHAR> *Ct, GUID const *Guid)
	{
		PostWorkItem(new NtdsLookupObjTypeGuidWorkItem(Ct, Lc, *Guid));
	}
	void LookupName(CompletionTarget<GUID> *Ct, PCWSTR Name)
	{
		PostWorkItem(new NtdsLookupObjTypeNameWorkItem(Ct, Lc, Name));
	}
};

struct GuidInhTypeTranslator : Lookup::Translator<GUID>
{
	auto_refct<LdapConnection> Lc;

	GuidInhTypeTranslator(LdapConnection *Lc) :
		Lc(Lc)
	{}
	GuidInhTypeTranslator(SDE_GENERIC_OPTS const &GenOpts, UCHAR Privileges) :
		Lc(new LdapConnection(Lc->Module, GenOpts, Privileges))
	{}
	void LookupData(CompletionTarget<WCHAR> *Ct, GUID const *Guid)
	{
		PostWorkItem(new NtdsLookupObjInhTypeGuidWorkItem(Ct, Lc, *Guid));
	}
	void LookupName(CompletionTarget<GUID> *Ct, PCWSTR Name)
	{
		PostWorkItem(new NtdsLookupObjInhTypeNameWorkItem(Ct, Lc, Name));
	}
};

}//namespace Ldap